﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AESyouhua
{
    class MixColumn
    {
        //private static int[] inLogTable =
        // {     //生成元为03的反对数表
        //       1,3,5,15,17,51,85,255,26,46,114,150,161,248,19,53,
        //       95,225,56,72,216,115,149,164,247,2,6,10,30,34,102,170,
        //       229,52,92,228,55,89,235,38,106,190,217,112,144,171,230,49,
        //       83,245,4,12,20,60,68,204,79,209,104,184,211,110,178,205,
        //       76,212,103,169,224,59,77,215,98,166,241,8,24,40,120,136,
        //       131,158,185,208,107,189,220,127,129,152,179,206,73,219,118,154,
        //       181,196,87,249,16,48,80,240,11,29,39,105,187,214,97,163,
        //       254,25,43,125,135,146,173,236,47,113,147,174,233,32,96,160,
        //       251,22,58,78,210,109,183,194,93,231,50,86,250,21,63,65,
        //       195,94,226,61,71,201,64,192,91,237,44,116,156,191,218,117,
        //       159,186,213,100,172,239,42,126,130,157,188,223,122,142,137,128,
        //       155,182,193,88,232,35,101,175,234,37,111,177,200,67,197,84 ,
        //       252,31,33,99,165,244,7,9,27,45,119,153,176,203,70,202,
        //       69,207,74,222,121,139,134,145,168,227,62,66,198,81,243,14,
        //       18,54,90,238,41,123,141,140,143,138,133,148,167,242,13,23,
        //       57,75,221,124,132,151,162,253,28,36,108,180,199,82,246,1
        //   };

        //public static int[,] colM = new int[4, 4] { { 2, 3, 1, 1 }, { 1, 2, 3, 1 }, { 1, 1, 2, 3 }, { 3, 1, 1, 2 } };

        public static int[] GetMixColumn(int[] cipher)
        {
            int[] mixcolumn2 = new int[16];

            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    //0,1,2,3  4,5,6,7                         0 ,4                  1 ,5                2 ,6                 3,7    0,1,2,3
                    mixcolumn2[j + i * 4] = SetMixcolumn(cipher[0 + i * 4], cipher[1 + i * 4], cipher[2 + i * 4], cipher[3 + i * 4], j + i * 4);
                }
            }
            return mixcolumn2;
        }
        private static int SetMixcolumn(int a, int b, int c, int d, int n)
        {
            int mixColumn2 = 0;

            switch (n % 4)
            {
                case 0:
                    {
                        mixColumn2 = mul3(a, b);
                        mixColumn2 = (mixColumn2 ^ b ^ c ^ d) % 256;
                        break;
                    }
                case 1:
                    {
                        mixColumn2 = mul3(b, c);
                        mixColumn2 = (mixColumn2 ^ a ^ c ^ d) % 256;
                        break;
                    }
                case 2:
                    {
                        mixColumn2 = mul3(c, d);
                        mixColumn2 = (mixColumn2 ^ a ^ b ^ d) % 256;
                        break;
                    }
                case 3:
                    {
                        mixColumn2 = mul3(a, d);
                        mixColumn2 = (mixColumn2 ^ a ^ b ^ c) % 256;
                        break;
                    }
            }
            return mixColumn2;
        }
        public static int[] InvMixColumn(int[] cipher)
        {
            //int[] invMixcolumn = new int[16];

            //for (int i = 0; i < 4; i++)
            //{
            //    for (int j = 0; j < 4; j++)
            //    {
            //        invMixcolumn[j + i * 4] = GetInvMixcolumn(cipher[0 + i * 4], cipher[1 + i * 4], cipher[2 + i * 4], cipher[3 + i * 4], j + i * 4);
            //    }
            //}
            //return invMixcolumn;
            int[] invMixcolumn2 = new int[16];
            int[] invMixcolumn3 = new int[16];
            for (int i = 0; i < 4; i++)
            {
                //轻量化转换
                for (int j = 0; j < 4; j++)
                {
                    invMixcolumn2[j + i * 4] = GetInvMixcolumn1(cipher[0 + i * 4], cipher[1 + i * 4], cipher[2 + i * 4], cipher[3 + i * 4], j + i * 4);
                }
                for (int j = 0; j < 4; j++)
                {
                    invMixcolumn3[j + i * 4] = SetMixcolumn(invMixcolumn2[0 + i * 4], invMixcolumn2[1 + i * 4], invMixcolumn2[2 + i * 4], invMixcolumn2[3 + i * 4], j + i * 4);
                }

            }
            return invMixcolumn3;
        }

        private static int GetInvMixcolumn1(int a, int b, int c, int d, int n)
        {
            int invmixColumn = 0;

            switch (n % 4)
            {
                case 0:
                    {
                        invmixColumn = mul4(a, c);
                        invmixColumn = (invmixColumn ^ a) % 256;
                        break;
                    }
                case 1:
                    {
                        invmixColumn = mul4(b, d);
                        invmixColumn = (invmixColumn ^ b) % 256;
                        break;
                    }
                case 2:
                    {
                        invmixColumn = mul4(a, c);
                        invmixColumn = (invmixColumn ^ c) % 256;
                        break;
                    }
                case 3:
                    {
                        invmixColumn = mul4(b, d);
                        invmixColumn = (invmixColumn ^ d) % 256;
                        break;
                    }
            }
            return invmixColumn;
        }

        //private static int GetInvMixcolumn(int a, int b, int c, int d, int n)
        //{
        //    int invmixColumn = 0;

        //    switch (n % 4)
        //    {
        //        case 0:
        //            {
        //                invmixColumn = (mule(a) ^ mulb(b) ^ muld(c) ^ mul9(d)) % 256;
        //                break;
        //            }
        //        case 1:
        //            {
        //                invmixColumn = (mul9(a) ^ mule(b) ^ mulb(c) ^ muld(d)) % 256;
        //                break;
        //            }
        //        case 2:
        //            {
        //                invmixColumn = (muld(a) ^ mul9(b) ^ mule(c) ^ mulb(d)) % 256;
        //                break;
        //            }
        //        case 3:
        //            {
        //                invmixColumn = (mulb(a) ^ muld(b) ^ mul9(c) ^ mule(d)) % 256;
        //                break;
        //            }
        //    }
        //    return invmixColumn;
        //}
        //private static int getNum(int num)
        //{
        //    int i = 0;
        //    for (; i < 256; i++)
        //    {
        //        if (num == inLogTable[i])
        //            break;
        //    }
        //    return i;
        //}

        private static int mul2(int x)
        {
            int mix = 0;
            if ((x >> 7 & 1) == 1)
                mix ^= (x << 1) ^ 0x1b;
            else
                mix ^= x << 1;
            return mix;
        }

        private static int mul3(int x, int s)
        {
            int sum = x ^ s;
            int mix = 0;
            if ((sum >> 7 & 1) == 1)
                mix ^= (sum << 1) ^ 0x1b;
            else
                mix ^= sum << 1;
            return mix;
        }

        private static int mul4(int x, int s)
        {
            int sum = x ^ s;
            int mix = 0;
            if ((sum >> 7 & 1) == 1)
                mix ^= (sum << 1) ^ 0x1b;
            else
                mix ^= sum << 1;
            mix = mul2(mix);
            return mix;
        }

        //private static int mul9(int x)
        //{
        //    int mix = x;
        //    for (int i = 0; i < 3; i++)
        //    {
        //        mix = mul2(mix) % 256;
        //    }
        //    mix ^= x;
        //    return mix;
        //}
        //private static int mulb(int x)
        //{
        //    int mix = 0;
        //    mix = mul2(x) ^ mul9(x);
        //    return mix;
        //}
        //private static int muld(int x)
        //{
        //    int mix = x;
        //    for (int i = 0; i < 2; i++)
        //    {
        //        mix = mul2(mix);
        //    }
        //    mix ^= mul9(x);
        //    return mix;
        //}
        //private static int mule(int x)
        //{
        //    int mix = x;
        //    int a = x;
        //    for (int i = 0; i < 3; i++)
        //    {
        //        mix = mul2(mix);
        //    }
        //    for (int i = 0; i < 2; i++)
        //    {
        //        a = mul2(a);
        //    }
        //    mix ^= a ^ mul2(x) % 256;
        //    return mix;
        //}
    }
}
